//********************************************************************
//	created:	10:2:2012   15:50
//	filename: 	rpcservice.h
//	author:		tiamo
//	purpose:	rpc service
//********************************************************************

#pragma once

//
// rpc service
//
namespace rpc
{
	//
	// rpc service
	//
	class Service : public ::Service
	{
	public:
		//
		// constructor
		//
		Service(UniString const& name, mysql::Database& database) : ::Service(name, database) {}

		//
		// destructor
		//
		virtual ~Service()													{}

	private:
		//
		// listen socket
		//
		class ListenSocket : public network::AsyncSocket
		{
		public:
			//
			// constructor
			//
			ListenSocket(Service* service) : AsyncSocket(0, 0)				{mService = service;}

			//
			// destructor
			//
			virtual ~ListenSocket()											{}

		private:
			//
			// network event
			//
			virtual void onNetworkEvent(bool readEvent, bool writeEvent, bool errorEvent);

		private:
			//
			// service
			//
			Service*														mService;
		};

		//
		// rpc request packet
		//
		class RpcRequestPacket : public network::BasePacket
		{
		public:
			//
			// constructor
			//
			RpcRequestPacket(void const* buffer, uint32_t length) : BasePacket(L"RpcRequestPacket"), mDataBuffer(buffer, length, false) {}

			//
			// destructor
			//
			virtual ~RpcRequestPacket()										{}

			//
			// get data buffer
			//
			utils::DataBuffer const& getDataBuffer() const					{return mDataBuffer;}

			//
			// get data buffer
			//
			utils::DataBuffer& getDataBuffer()								{return mDataBuffer;}

		private:
			//
			// data buffer
			//
			utils::DataBuffer												mDataBuffer;
		};

		//
		// method 
		//
		typedef std::function<void(UniString const&, xmlrpc::ArrayValue const*, network::AsyncSocket*)> Method;

	private:
		//
		// initialize
		//
		virtual void initialize();

		//
		// create listen socket
		//
		void createListenSocket(UniString const& localAddress, uint32_t localPort);

		//
		// setup client socket
		//
		void setupClientSocket(utils::SmartPointer<network::AsyncSocket> const& clientSocket);

		//
		// add method
		//
		void addMethod(UniString const& name, Method&& method);

		//
		// send response
		//
		void sendResponse(network::AsyncSocket* theSocket, xmlrpc::Value const* response, bool isFault = false);

		//
		// send fault message
		//
		void sendFaultMessage(network::AsyncSocket* theSocket, int32_t faultCode, wchar_t const* messageFormat, ...);

		//
		// save category
		//
		void onSaveCategory(utils::BaseRequest* theRequest);

		//
		// upload category
		//
		void onUploadCategory(UniString const& methodName, xmlrpc::ArrayValue const* paramList, network::AsyncSocket* theSocket);

		//
		// socket connected
		//
		void onSocketConnected(network::AsyncSocket* theSocket, bool errorState);

		//
		// socket closed
		//
		void onSocketClosed(network::AsyncSocket* theSocket, bool errorState);

		//
		// socket decode packet
		//
		utils::SmartPointer<network::BasePacket> onSocketDecodePacket(network::AsyncSocket* theSocket, void const* dataBuffer, uint16_t dataLength, uint32_t& usedLength);

		//
		// socket data
		//
		void onSocketPacket(network::AsyncSocket* theSocket, network::BasePacket* thePacket);

	private:
		//
		// method list
		//
		std::map<UniString, Method>											mMethodList;
	};
}
